package lxs.swift.tool;

import org.jetbrains.annotations.Nullable;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

public class Generics {
    /**
     * 获取接口上的泛型T
     *
     * @param clazz      类
     * @param interfaceC 类上接口
     * @param index      类上接口的泛型索引
     */
    @Nullable
    public static Class<?> getInterfaceT(Class<?> clazz, Class<?> interfaceC, int index) {
        //不是子类
        if (!interfaceC.isAssignableFrom(clazz)) {
            return null;
        }
        Type[] types = clazz.getGenericInterfaces();
        for (Type type : types) {
            if (type instanceof ParameterizedType) {
                ParameterizedType parameterizedType = (ParameterizedType) type;
                if (parameterizedType.getRawType() == interfaceC) {
                    Type actualTypeArgument = parameterizedType.getActualTypeArguments()[index];
                    if (actualTypeArgument instanceof Class<?>) {
                        return (Class<?>) actualTypeArgument;
                    } else if (actualTypeArgument instanceof ParameterizedType) {
                        ParameterizedType pt = (ParameterizedType) actualTypeArgument;
                        Type rawType = pt.getRawType();
                        return ((Class<?>) rawType);
                    } else {
                        return null;
                    }
                }
            }
        }
        Class<?> superclass = clazz.getSuperclass();
        if (interfaceC.isAssignableFrom(superclass)) {
            return getInterfaceT(superclass, interfaceC, index);
        }
        return null;
    }


    /**
     * 获取类的父类上的泛型T
     *
     * @param clazz 类
     * @param index 泛型索引
     */
    public static Class<?> getClassT(Class<?> clazz, int index) {
        Type type = clazz.getGenericSuperclass();
        return checkType(type, index);
    }

    private static Class<?> checkType(Type type, int index) {
        if (type instanceof Class<?>) {
            return (Class<?>) type;
        } else if (type instanceof ParameterizedType) {
            ParameterizedType pt = (ParameterizedType) type;
            Type t = pt.getActualTypeArguments()[index];
            return checkType(t, index);
        } else {
            return null;
        }
    }
}
